﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Ivi.Driver.Interop;
using System.Text.RegularExpressions;
using Ivi.ConfigServer.Interop;
using System.Globalization;
using System.Reflection;
using System.Diagnostics;

namespace AIRO.Devices
{

    
    [Guid("19E91308-4419-11DD-A0EA-335256D89593")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("MyDevices.BasicIviDriver")]
    public abstract class BasicIviDriver : IIviDriverIdentity, IIviComponentIdentity, IIviDriverOperation
    {
        protected string _description;
        protected string _identifier;
        protected string _instrumentManufacturer;
        protected string _vendor;
        protected string _supportedInstrumentModels;
        protected bool _interchangeCheck;
        protected string _logicalName;
        protected bool _queryInstrumentStatus;
        protected bool _rangeCheck;
        protected bool _recordCoercions;
        protected bool _simulate;
        protected bool _cache;
        protected string _driverSetup;
        protected string resourceName;        
        protected bool _initialized = false;
        protected System.Collections.Generic.Queue<string> interchangeWarningQueue = new Queue<string>();
        protected System.Collections.Generic.Queue<Error> iviDriverErrorQueue = new Queue<Error>();
        protected System.Collections.Generic.Queue<CoercionRecord> coercionRecordQueue = new Queue<CoercionRecord>();

        protected NumberFormatInfo numericFormatProvider = new NumberFormatInfo();

        protected BasicIviDriver()
        {
            _description = "Ivi Basic Custom driver";
            _identifier = "Test Device";
            _instrumentManufacturer = "No Name";
            _vendor = "Anton A Fortunatov";
            _supportedInstrumentModels = "For testing purpose only!";
            numericFormatProvider.PercentDecimalSeparator = ".";
            numericFormatProvider.CurrencyDecimalSeparator = ".";
            numericFormatProvider.NumberDecimalSeparator = ".";
            
        }

        [Guid("680CDC96-43CD-11DD-9302-496456D89593")]
        public struct Error
        {
            private int _errorCode;
            private string _errorMessage;
            public int ErrorCode
            {
                get { return _errorCode; }
            }
            public string ErrorMessage
            {
                get { return _errorMessage; }
            }

            public Error(int errorCode, string errorMessage)
            {
                this._errorCode = errorCode;
                this._errorMessage = errorMessage;
            }
            public Error(IviDriver_ErrorCodes code)
            {
                this._errorCode = (int)code;
                this._errorMessage = code.ToString();
            }

        }

        [Guid("B8270960-43CB-11DD-9FD8-065356D89593")]
        public struct CoercionRecord
        {
            private string _attributeName;
            private string _repeatedCapabilityID;
            private string _desiredVal;
            private string _coercedVal;

            public CoercionRecord(string attributeName, string repeatedCapabilityID, string desiredVal, string coercedVal)
            {
                this._attributeName = attributeName;
                this._repeatedCapabilityID = repeatedCapabilityID;
                this._desiredVal = desiredVal;
                this._coercedVal = coercedVal;
            }

            public CoercionRecord(string attributeName, string desiredVal, string coercedVal)
                : this(attributeName, "", desiredVal, coercedVal)
            {

            }

            override public string ToString()
            {
                if (_repeatedCapabilityID != "")
                {
                    return "Attribute " + _attributeName + " on " + _repeatedCapabilityID + " was coerced from " + _desiredVal + " to " + _coercedVal;
                }
                else
                {
                    return "Attribute " + _attributeName + " was coerced from " + _desiredVal + " to " + _coercedVal;
                }
            }
        }

        #region IIviDriver Members

        #region Properties

        public virtual IIviDriverOperation DriverOperation
        {
            get { return (IIviDriverOperation)this; }
        }

        public virtual IIviDriverIdentity Identity
        {
            get { return (IIviDriverIdentity)this; }
        }

        public virtual bool Initialized
        {
            get { return _initialized; }
        }

        public virtual IIviDriverUtility Utility
        {
            get { return (IIviDriverUtility)this; }
        }
        #endregion

        #region Methods

        protected virtual void ParseOptionString(string OptionString)
        {
            const string optionStringPattern = @"((?<Name>DriverSetup)=(?<Value>.*)$)|((?<Name>[^=;\s,]+)=(?<Value>[^;\s,]*)(,|$))";
            Regex optionStringRegex = new Regex(optionStringPattern, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match m = optionStringRegex.Match(OptionString);
            while (m.Success)
            {
                string name = m.Groups["Name"].Value;
                string value = m.Groups["Value"].Value;

                switch (name.ToLower())
                {
                    case "rangecheck":
                        try
                        {
                            _rangeCheck = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "queryinstrstatus":
                        try
                        {
                            _queryInstrumentStatus = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "cache":
                        try
                        {
                            _cache = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "simulate":
                        try
                        {
                            _simulate = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "recordcoercions":
                        try
                        {
                            _recordCoercions = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "interchangecheck":
                        try
                        {
                            _interchangeCheck = ParseBoolean(value);
                        }
                        catch (ArgumentException e)
                        {
                        }
                        break;
                    case "driversetup":
                        _driverSetup = value;
                        break;
                    default:
                        iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_BAD_OPTION_NAME));
                        break;
                }


                m = m.NextMatch();
            }
        }

        protected virtual IviDriverSession ReadConfigStore()
        {
            Debug.WriteLine("I'm reading config");
            IviConfigStoreClass configStore = new IviConfigStoreClass();
            IviDriverSession iviSession;
            string location;
            if (configStore.ProcessDefaultLocation != "")
            {
                location = configStore.ProcessDefaultLocation;
            }
            else if (configStore.MasterLocation != "")
            {
                location = configStore.MasterLocation;
            }
            else
            {
                throw new Exception("Process Default Location and Master Location are null strings!");
            }
            configStore.Deserialize(location);
            iviSession = configStore.GetDriverSession(_logicalName);
            if (iviSession != null)
            {
                _rangeCheck = iviSession.RangeCheck;
                _cache = iviSession.Cache;
                _queryInstrumentStatus = iviSession.QueryInstrStatus;
                _simulate = iviSession.Simulate;
                _driverSetup = iviSession.DriverSetup;
                _recordCoercions = iviSession.RecordCoercions;
                _interchangeCheck = iviSession.InterchangeCheck;
                if (iviSession.HardwareAsset != null)
                {
                    resourceName = iviSession.HardwareAsset.IOResourceDescriptor;
                }
                else
                    resourceName = "";
                return iviSession;
            }
            else
                throw new Exception("Can't get driver session by logical name");
        }

        protected virtual bool ParseBoolean(string str)
        {
            str = str.ToLower();
            if ((str == "true") | (str == "1") | (str == "vi_true"))
                return true;
            else if ((str == "false") | (str == "0") | (str == "vi_false"))
                return false;
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_BAD_OPTION_VALUE));
                throw new ArgumentException();
            }
        }

        #endregion        

        #endregion

        #region IIviDriverIdentity Members

        #region Properties

        public virtual string Description
        {
            get { return _description; }
        }

        public virtual string GroupCapabilities
        {
            get { return ""; }
        }

        public virtual string Identifier
        {
            get { return _identifier; }
        }

        public virtual string InstrumentFirmwareRevision
        {
            get
            {
                if (_initialized)
                {
                    if (Simulate)
                        return "Not available while simulating";
                    else
                    {
                        return "Cannot query from instrument";
                    }
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    return "";
                }
            }
        }

        public virtual string InstrumentManufacturer
        {
            get
            {
                if (_initialized)
                {
                    return _instrumentManufacturer;
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    return "";
                }
            }
        }

        public virtual string InstrumentModel
        {
            get
            {
                if (_initialized)
                {
                    if (Simulate)
                        return "Not available while simulating";
                    else
                    {
                        return "Cannot query from instrument";
                    }
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    return "";
                }
            }

        }

        public virtual string Revision
        {
            get { return Assembly.GetCallingAssembly().GetName().Version.ToString(); }
        }

        public virtual int SpecificationMajorVersion
        {
            get { return 0; }
        }

        public virtual int SpecificationMinorVersion
        {
            get { return 0; }
        }

        public virtual string SupportedInstrumentModels
        {
            get { return _supportedInstrumentModels; }
        }

        public virtual string Vendor
        {
            get { return _vendor; }
        }
        #endregion

        #endregion

        #region IIviDriverUtility Members

        #region Methods
                
        public virtual void ErrorQuery(ref int ErrorCode, ref string ErrorMessage)
        {

            if (iviDriverErrorQueue.Count > 0)
            {
                Error err = iviDriverErrorQueue.Dequeue();
                ErrorCode = err.ErrorCode;
                ErrorMessage = err.ErrorMessage;
            }
            else
            {

            }

        }

        public virtual void LockObject()
        {
            iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_METHOD_NOT_SUPPORTED));
            //throw new NotImplementedException();
        }

        public virtual void Reset()
        {
            if (_initialized)
            {               

                interchangeWarningQueue.Enqueue("User called the Reset function");
                //throw new NotImplementedException();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        public virtual void ResetWithDefaults()
        {
            if (_initialized)
            {
                Reset();
            }

            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
            }
        }

        public virtual void SelfTest(ref int TestResult, ref string TestMessage)
        {
            TestResult = 0;
            TestMessage = "Not implemented yet!";
        }

        public virtual void UnlockObject()
        {
            iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_METHOD_NOT_SUPPORTED));
        }

        #endregion

        #endregion

        #region IIviDriverOperation Members

        #region Properties

        public virtual bool Cache
        {
            get
            {
                return _cache;
            }
            set
            {
                _cache = value;
            }
        }

        public virtual string DriverSetup
        {
            get { return _driverSetup; }
        }

        public virtual bool InterchangeCheck
        {
            get
            {
                return _interchangeCheck;
            }
            set
            {
                _interchangeCheck = value;

            }
        }

        public virtual string IoResourceDescriptor
        {
            get
            {
                if (_initialized)
                {
                    return resourceName;
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    return "";
                }
            }
        }

        public virtual string LogicalName
        {
            get
            {
                if (_initialized)
                {
                    return _logicalName;
                }
                else
                {
                    iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                    return "";
                }
            }
        }

        public virtual bool QueryInstrumentStatus
        {
            get
            {
                return _queryInstrumentStatus;
            }
            set
            {
                _queryInstrumentStatus = value;
            }
        }

        public virtual bool RangeCheck
        {
            get
            {
                return _rangeCheck;
            }
            set
            {
                _rangeCheck = value;
            }
        }

        public virtual bool RecordCoercions
        {
            get
            {
                return _recordCoercions;
            }
            set
            {
                _recordCoercions = value;
            }
        }

        public virtual bool Simulate
        {
            get
            {
                return _simulate;
            }
            set
            {
                _simulate = value;
            }
        }

        #endregion

        #region Methods

        public virtual void ClearInterchangeWarnings()
        {
            interchangeWarningQueue.Clear();
        }

        public virtual string GetNextCoercionRecord()
        {
            if ((coercionRecordQueue.Count > 0) & (_initialized))
            {
                CoercionRecord coercionRecord = coercionRecordQueue.Dequeue();
                return coercionRecord.ToString();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                return "";

            }
        }

        public virtual string GetNextInterchangeWarning()
        {
            if ((interchangeWarningQueue.Count > 0) & (_initialized))
            {
                return interchangeWarningQueue.Dequeue();
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_NOT_INITIALIZED));
                return "";
            }
        }

        public virtual void InvalidateAllAttributes()
        {
            throw new NotImplementedException();
        }        

        public virtual void ResetInterchangeCheck()
        {
            throw new NotImplementedException();
        }

        #endregion

        #endregion

 
        

    }
}
